<template>
  <div
    style=" overflow: hidden;border:1px solid #cccccc;margin:20px"
    v-bind:style="{ width: width + 'px', height: height + 'px' }"
  >
    <canvas
      id="fabric_canvas"
      :height="height"
      :width="width"
      style="cursor:pointer"
    >
    </canvas>
  </div>
</template>

<script>
import { fabric } from "fabric";
import DrawRectHandler from "./DrawRectHandler";
import DrawCircleHandler from "./DrawCircleHandler";
import DrawLineHandler from "./DrawLineHandler";
import DrawPointHandler from "./DrawPointHandler";
import moveHandler from "./moveHandler";
import wheelHandler from "./wheelHandler";
import DrawSelectHandler from "./DrawSelectHandler";
import DrawLabelHandler from "./DrawLabelHandler";
export default {
  props: {
    drawType: { type: String },
    disabled: { type: Boolean, default: false },
    width: { type: Number, default: 700 },
    height: { type: Number, default: 500 },
    src: {
      type: String,
      default: "",
    },
    data: {
      type: Array,
      default() {
        return [
          {
            id: new Date().getTime() + "_Rect",
            drawType: "Rect",
            pointers: [
              { x: 0, y: 0 },
              { x: 0, y: 0 },
            ],
            drawOptions:{},//绘制属性，如果指定则按指定的属性覆盖
          },
          {
            id: new Date().getTime() + "_Line",
            drawType: "Line",
            pointers: [
              { x: 0, y: 0 },
              { x: 0, y: 0 },
            ],
            drawOptions:{},//绘制属性，如果指定则按指定的属性覆盖
          },
          {
            id: new Date().getTime() + "_Point",
            drawType: "Point",
            pointers: [{ x: 0, y: 0 }],
            drawOptions:{},//绘制属性，如果指定则按指定的属性覆盖
          },
          {
            id: new Date().getTime() + "_Circle",
            drawType: "Circle",
            pointers: [
              { x: 0, y: 0 },
              { x: 0, y: 0 },
            ],
            drawOptions:{},//绘制属性，如果指定则按指定的属性覆盖
          },
          {
            id: new Date().getTime() + "_Label",
            drawType: "Label",
            text: new Date().getTime(),
            pointers: [{ x: 0, y: 90 }],
            drawOptions:{},//绘制属性，如果指定则按指定的属性覆盖
          },
        ];
      },
    },
  },
  data() {
    return {
      loading: false,
      canvas: null,
      oldDrawHandler: null,
      currentDrawType: "",
      currentDrawHandler: "",
      drawHandlers: {
        DrawRectHandler,
        DrawCircleHandler,
        DrawLineHandler,
        DrawPointHandler,
        moveHandler,
        wheelHandler,
        DrawSelectHandler,
        DrawLabelHandler,
      },
      drawOptions: [],
      imgObj: null,
    };
  },
  computed: {
    drawTypes() {
      return Object.keys(this.drawHandlers);
    },
  },
  watch: {
    height() {
      this.drawInit();
    },
    width() {
      this.drawInit();
    },
    src() {
      this.loadImg(this.src);
    },
    data: {
      deep: true,
      handler() {
        this.reloadDrawOptionsFromData();
      },
    },
    drawType() {
      this.changeDrawType(this.drawType)
    },
  },
  computed: {
    drawHandler() {
      return this.drawHandlers[this.currentDrawHandler];
    },
  },
  mounted() {
    this.initHandler();
    this.drawInit();
    
  },
  methods: {
    setSelectable(selectable) {
      if (selectable) {
        this.canvas.selection = true;
        this.canvas.selectionColor = this.canvas.selectionBorderColor =
          "rgba(100, 100, 255, 0.2)"; // 边框和选中的颜色
        this.drawOptions.forEach((options) => {
          options.fabricObj.set({ selectable: true, });
        });
      } else {
        this.canvas.selection = false;
        this.canvas.selectionColor = this.canvas.selectionBorderColor =
          "rgba(100, 100, 255, 0)"; // 边框和选中的颜色
        this.drawOptions.forEach((options) => {
          options.fabricObj.set({ selectable: false });
        });
      }
    },
    __mapOptions(drawOptions) {
      return {
        id: drawOptions.id,
        drawType: drawOptions.drawType,
        pointers: [...(drawOptions.pointers || [])],
        bindId: drawOptions.bindId,
        text: drawOptions.text,
        drawOptions:drawOptions.drawOptions,
      };
    },
    __drawn(drawObj) {
      this.drawOptions.push(drawObj);
      var newOptions = this.__mapOptions(drawObj);
      this.data.push(newOptions);
      this.$emit("drawn", newOptions);
    },
    initHandler() {
      Object.keys(this.drawHandlers).forEach((key) => {
        if (this.drawHandlers[key].onDrawn) {
          this.drawHandlers[key].onDrawn((res) => {
            this.__drawn(res);
          });
        }
      });
    },
    drawInit() {
      if (this.canvas) this.canvas.dispose();

      this.canvas = new fabric.Canvas("fabric_canvas");
      // this.canvas.selections = false; // 禁止所有选中
      this.canvas.selectionColor = this.canvas.selectionBorderColor =
        "rgba(100, 100, 255, 0)"; // 边框和选中的颜色

      this.$nextTick(() => {
        this.canvas.on("mouse:down", (opt) => {
          // console.log("mousedown", opt);

          var evt = opt.e;
          if (evt.altKey === true) {
            if (this.currentDrawHandler != "moveHandler") {
              this.oldDrawHandler = this.currentDrawHandler;
              this.currentDrawHandler = "moveHandler";
            }
          } else {
            this.currentDrawHandler =
              this.oldDrawHandler || this.currentDrawHandler;
          }
          if (!this.drawHandler) return;
          this.drawHandler.onMousedown(opt, this.canvas);
        });
        this.canvas.on("mouse:move", (opt) => {
          // console.log("mousemove", opt);
          if (!this.drawHandler) return;
          this.drawHandler.onMousemove(opt, this.canvas);
        });
        this.canvas.on("mouse:up", (opt) => {
          // console.log("mouseup", opt);
          if (!this.drawHandler) return;
          this.drawHandler.onMouseup(opt, this.canvas);
        });

        this.canvas.on("mouse:wheel", (opt) => {
          wheelHandler.onMousewheel(opt, this.canvas);
          this.redrawByDrawOptions(this.drawOptions);
        });

        //画布载入完后载入图片
        this.loadImg(this.src);
      });
    },
    changeDrawType(drawType) {
      this.currentDrawHandler = "Draw" + drawType+ "Handler";
      if (drawType == "Select") this.setSelectable(true);
      else this.setSelectable(false);
      // console.log(this.drawOptions);
    },
    undo() {
      this.data.pop();
    },
    clear() {
      while (this.data.length > 0) this.data.pop();
    },
    loadImg(url) {
      let _this = this;
      this.loading = true;
      this.canvas.set({ width: this.width, height: this.height });
      if (this.imgObj){
        debugger
         this.canvas.remove(this.imgObj);
         this.imgObj.dispose();
      }
      fabric.Image.fromURL(url, (oImg) => {
        _this.$emit('loaded')
        _this.loading = false;
        _this.imgObj = oImg;
        // 将其缩小，然后将其翻转，然后再将其添加到画布上
        var scaleRate = _this.getScaleRate(
          oImg.height,
          oImg.width,
          _this.canvas.height,
          _this.canvas.width
        );
        var canvasWidth = _this.canvas.width * scaleRate;
        var canvasHeight = _this.canvas.height * scaleRate;
        var zoomRate = _this.canvas.height / canvasHeight;

        //画布居中:计算缩放后的大小差值
        var left = (_this.canvas.width - oImg.width * zoomRate) / 2;
        var top = (_this.canvas.height - oImg.height * zoomRate) / 2;

        _this.canvas.setHeight(canvasHeight);
        _this.canvas.setWidth(canvasWidth);
        _this.canvas.setZoom(zoomRate);
        oImg.set({
          selectable: false,
          defaultCursor: "default",
          hoverCursor: "default",
        });
        _this.canvas.insertAt(oImg, 0,false);
        var vpt = _this.canvas.viewportTransform;
        vpt[4] = left;
        vpt[5] = top;
        _this.canvas.setViewportTransform(_this.canvas.viewportTransform);
        //重绘标注
        // _this.redrawByDrawOptions(this.drawOptions);
        _this.reloadDrawOptionsFromData();
        _this.canvas.renderAll();
        
      });
    },
    getScaleRate(imgHeight, imgWidth, canvasHeight, canvasWidth) {
      var isCanvasHeightRate = canvasHeight / canvasWidth;
      var isImgHeightRate = imgHeight / imgWidth;
      //如果 图片高度比小于画布高度比，则以宽度为主
      //如果 图片高度比大于画布高度比，则以高度为主
      if (isImgHeightRate > isCanvasHeightRate) {
        return imgHeight / canvasHeight;
      } else {
        return imgWidth / canvasWidth;
      }
    },
    removeById(id) {
      var newData=[];
      while(this.data.length>0)
      {
        var item = this.data.pop();
        if(item.id!=id&&item.bindId!=id)
          newData.push(item);
      }
      this.data.push.apply(this.data,newData)
      this.$emit('change',[...this.data]);
    },
    remove(removeIds) {
     
      var removeObjs = this.drawOptions.filter(d=>removeIds.indexOf(d.id)>-1||removeIds.indexOf(d.bindId)>-1)
      removeObjs.forEach(drawObj=>{
        let drawHandler = "Draw" + drawObj.drawType + "Handler";
        this.drawHandlers[drawHandler].remove(this.canvas, drawObj);
        drawObj=null;
      })
      
    },
    draw(drawObj) {
      let drawHandler = "Draw" + drawObj.drawType + "Handler";
      this.drawHandlers[drawHandler].draw(this.canvas, drawObj, this.data);
    },
    redrawByDrawOptions(drawOptions) {
      if (!drawOptions) return;
      drawOptions.forEach((drawObj) => {
        this.draw(drawObj);
      });
    },
    reloadDrawOptionsFromData() {
      var newIds = this.data.map((d) => d.id);
      //移除旧的options
      var removeIds = [];
      this.drawOptions.forEach((d) => {
        if (newIds.indexOf(d.id) == -1) {
          removeIds.push(d.id);
        }
      });
      this.remove(removeIds)
      //补充新的
      this.drawOptions =this.drawOptions.filter(d=>removeIds.indexOf(d.id)==-1);
      var oldIds = this.drawOptions.map((d) => d.id);

      this.data.forEach((d) => {
        if (oldIds.indexOf(d.id) == -1) {
          this.drawOptions.push(this.__mapOptions(d));
        }
      });
      this.redrawByDrawOptions(this.drawOptions);
    },
    resize() {
      this.loadImg(this.src);
    },
    isCurrentDrawType(drawType) {
      return this.currentDrawType == drawType;
    },
  },
};
</script>

<style></style>
